home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / 92052tar.gz / 920528.tar / tcpsubr.c < prev    next >
C/C++ Source or Header  |  1992-05-28  |  7KB  |  337 lines

  1. /* @(#) $Header: tcpsubr.c,v 1.10 92/05/28 13:50:37 deyke Exp $ */
  2.  
  3. /* Low level TCP routines:
  4.  *  control block management
  5.  *  sequence number logical operations
  6.  *  state transitions
  7.  *  RTT cacheing
  8.  *  garbage collection
  9.  *
  10.  * Copyright 1991 Phil Karn, KA9Q
  11.  */
  12. #include <stdio.h>
  13. #include "global.h"
  14. #include "timer.h"
  15. #include "mbuf.h"
  16. #include "netuser.h"
  17. #include "internet.h"
  18. #include "tcp.h"
  19. #include "ip.h"
  20.  
  21. /* TCP connection states */
  22. char *Tcpstates[] = {
  23.     "",
  24.     "Closed",
  25.     "Listen",
  26.     "SYN sent",
  27.     "SYN received",
  28.     "Established",
  29.     "FIN wait 1",
  30.     "FIN wait 2",
  31.     "Close wait",
  32.     "Last ACK",
  33.     "Closing",
  34.     "Time wait"
  35. };
  36.  
  37. /* TCP closing reasons */
  38. char *Tcpreasons[] = {
  39.     "Normal",
  40.     "Reset/Refused",
  41.     "Timeout",      /* Not actually used */
  42.     "ICMP"          /* Not actually used */
  43. };
  44. struct tcb *Tcbs;               /* Head of control block list */
  45. int16 Tcp_mss = DEF_MSS;        /* Maximum segment size to be sent with SYN */
  46. int32 Tcp_irtt = DEF_RTT;       /* Initial guess at round trip time */
  47. int Tcp_trace;                  /* State change tracing flag */
  48. int Tcp_syndata;
  49. struct tcp_rtt Tcp_rtt[RTTCACHE];
  50. struct mib_entry Tcp_mib[] = {
  51.     NULLCHAR,               0,
  52.     "tcpRtoAlgorithm",      4,      /* Van Jacobsen's algorithm */
  53.     "tcpRtoMin",            0,      /* No lower bound */
  54.     "tcpRtoMax",            MAXINT32,       /* No upper bound */
  55.     "tcpMaxConn",           -1L,    /* No limit */
  56.     "tcpActiveOpens",       0,
  57.     "tcpPassiveOpens",      0,
  58.     "tcpAttemptFails",      0,
  59.     "tcpEstabResets",       0,
  60.     "tcpCurrEstab",         0,
  61.     "tcpInSegs",            0,
  62.     "tcpOutSegs",           0,
  63.     "tcpRetransSegs",       0,
  64.     NULLCHAR,               0,      /* Connection state goes here */
  65.     "tcpInErrs",            0,
  66.     "tcpOutRsts",           0,
  67. };
  68.  
  69. /* Look up TCP connection
  70.  * Return TCB pointer or NULLTCB if nonexistant.
  71.  * Also move the entry to the top of the list to speed future searches.
  72.  */
  73. struct tcb *
  74. lookup_tcb(conn)
  75. register struct connection *conn;
  76. {
  77.     register struct tcb *tcb;
  78.     struct tcb *tcblast = NULLTCB;
  79.  
  80.     for(tcb=Tcbs;tcb != NULLTCB;tcblast = tcb,tcb = tcb->next){
  81.         /* Yet another structure compatibility hack */
  82.         if(conn->remote.port == tcb->conn.remote.port
  83.          && conn->local.port == tcb->conn.local.port
  84.          && conn->remote.address == tcb->conn.remote.address
  85.          && conn->local.address == tcb->conn.local.address){
  86.             if(tcblast != NULLTCB){
  87.                 /* Move to top of list */
  88.                 tcblast->next = tcb->next;
  89.                 tcb->next = Tcbs;
  90.                 Tcbs = tcb;
  91.             }
  92.             return tcb;
  93.         }
  94.  
  95.     }
  96.     return NULLTCB;
  97. }
  98.  
  99. /* Create a TCB, return pointer. Return pointer if TCB already exists. */
  100. struct tcb *
  101. create_tcb(conn)
  102. struct connection *conn;
  103. {
  104.     register struct tcb *tcb;
  105.     struct tcp_rtt *tp;
  106.  
  107.     if((tcb = lookup_tcb(conn)) != NULLTCB)
  108.         return tcb;
  109.     tcb = (struct tcb *)callocw(1,sizeof (struct tcb));
  110.     ASSIGN(tcb->conn,*conn);
  111.  
  112.     tcb->state = TCP_CLOSED;
  113.     tcb->cwind = tcb->mss = Tcp_mss;
  114.     tcb->ssthresh = 65535;
  115.     if((tp = rtt_get(tcb->conn.remote.address)) != NULLRTT){
  116.         tcb->srtt = tp->srtt;
  117.         tcb->mdev = tp->mdev;
  118.     } else {
  119.         tcb->srtt = Tcp_irtt;   /* mdev = 0 */
  120.     }
  121.     /* Initialize timer intervals */
  122.     set_timer(&tcb->timer,tcb->srtt);
  123.     tcb->timer.func = tcp_timeout;
  124.     tcb->timer.arg = tcb;
  125.  
  126.     tcb->next = Tcbs;
  127.     Tcbs = tcb;
  128.     return tcb;
  129. }
  130.  
  131. /* Close our TCB */
  132. void
  133. close_self(tcb,reason)
  134. register struct tcb *tcb;
  135. int reason;
  136. {
  137.     struct reseq *rp1;
  138.     register struct reseq *rp;
  139.  
  140.     if(tcb == NULLTCB)
  141.         return;
  142.  
  143.     stop_timer(&tcb->timer);
  144.     tcb->reason = reason;
  145.  
  146.     /* Flush reassembly queue; nothing more can arrive */
  147.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  148.         rp1 = rp->next;
  149.         free_p(rp->bp);
  150.         free((char *)rp);
  151.     }
  152.     tcb->reseq = NULLRESEQ;
  153.     setstate(tcb,TCP_CLOSED);
  154. }
  155.  
  156. /* Sequence number comparisons
  157.  * Return true if x is between low and high inclusive,
  158.  * false otherwise
  159.  */
  160. int
  161. seq_within(x,low,high)
  162. register int32 x,low,high;
  163. {
  164.     if(low <= high){
  165.         if(low <= x && x <= high)
  166.             return 1;
  167.     } else {
  168.         if(low >= x && x >= high)
  169.             return 1;
  170.     }
  171.     return 0;
  172. }
  173. int
  174. seq_lt(x,y)
  175. register int32 x,y;
  176. {
  177.     int32 bugfix;
  178.     return (long)(bugfix=x-y) < 0;
  179. }
  180. #ifdef  notdef
  181. int
  182. seq_le(x,y)
  183. register int32 x,y;
  184. {
  185.     int32 bugfix;
  186.     return (long)(bugfix=x-y) <= 0;
  187. }
  188. #endif  /* notdef */
  189. int
  190. seq_gt(x,y)
  191. register int32 x,y;
  192. {
  193.     int32 bugfix;
  194.     return (long)(bugfix=x-y) > 0;
  195. }
  196. int
  197. seq_ge(x,y)
  198. register int32 x,y;
  199. {
  200.     int32 bugfix;
  201.     return (long)(bugfix=x-y) >= 0;
  202. }
  203.  
  204. void
  205. setstate(tcb,newstate)
  206. register struct tcb *tcb;
  207. register int newstate;
  208. {
  209.     register char oldstate;
  210.  
  211.     oldstate = tcb->state;
  212.     tcb->state = newstate;
  213.     if(Tcp_trace)
  214.         printf("TCB %lx %s -> %s\n",ptol(tcb),
  215.          Tcpstates[oldstate],Tcpstates[newstate]);
  216.  
  217.     /* Update MIB variables */
  218.     switch(oldstate){
  219.     case TCP_CLOSED:
  220.         if(newstate == TCP_SYN_SENT)
  221.             tcpActiveOpens++;
  222.         break;
  223.     case TCP_LISTEN:
  224.         if(newstate == TCP_SYN_RECEIVED)
  225.             tcpPassiveOpens++;
  226.         break;
  227.     case TCP_SYN_SENT:
  228.         if(newstate == TCP_CLOSED)
  229.             tcpAttemptFails++;
  230.         break;
  231.     case TCP_SYN_RECEIVED:
  232.         switch(newstate){
  233.         case TCP_CLOSED:
  234.         case TCP_LISTEN:
  235.             tcpAttemptFails++;
  236.             break;
  237.         }
  238.         break;
  239.     case TCP_ESTABLISHED:
  240.     case TCP_CLOSE_WAIT:
  241.         switch(newstate){
  242.         case TCP_CLOSED:
  243.         case TCP_LISTEN:
  244.             tcpEstabResets++;
  245.             break;
  246.         }
  247.         tcpCurrEstab--;
  248.         break;
  249.     }
  250.     if(newstate == TCP_ESTABLISHED || newstate == TCP_CLOSE_WAIT)
  251.         tcpCurrEstab++;
  252.  
  253.     if(tcb->s_upcall)
  254.         (*tcb->s_upcall)(tcb,oldstate,newstate);
  255.  
  256.     switch(newstate){
  257.     case TCP_SYN_RECEIVED:  /***/
  258.     case TCP_ESTABLISHED:
  259.         /* Notify the user that he can begin sending data */
  260.         if(tcb->t_upcall && tcb->window > tcb->sndcnt)
  261.             (*tcb->t_upcall)(tcb,tcb->window - tcb->sndcnt);
  262.         break;
  263.     }
  264. }
  265. /* Round trip timing cache routines.
  266.  * These functions implement a very simple system for keeping track of
  267.  * network performance for future use in new connections.
  268.  * The emphasis here is on speed of update (rather than optimum cache hit
  269.  * ratio) since rtt_add is called every time a TCP connection updates
  270.  * its round trip estimate.
  271.  */
  272. void
  273. rtt_add(addr,rtt)
  274. int32 addr;             /* Destination IP address */
  275. int32 rtt;
  276. {
  277.     register struct tcp_rtt *tp;
  278.     int32 abserr;
  279.  
  280.     if(addr == 0)
  281.         return;
  282.     tp = &Tcp_rtt[(unsigned short)addr % RTTCACHE];
  283.     if(tp->addr != addr){
  284.         /* New entry */
  285.         tp->addr = addr;
  286.         tp->srtt = rtt;
  287.         tp->mdev = 0;
  288.     } else {
  289.         /* Run our own SRTT and MDEV integrators, with rounding */
  290.         abserr = (rtt > tp->srtt) ? rtt - tp->srtt : tp->srtt - rtt;
  291.         tp->srtt = ((AGAIN-1)*tp->srtt + rtt + (AGAIN/2)) >> LAGAIN;
  292.         tp->mdev = ((DGAIN-1)*tp->mdev + abserr + (DGAIN/2)) >> LDGAIN;
  293.     }
  294. }
  295. struct tcp_rtt *
  296. rtt_get(addr)
  297. int32 addr;
  298. {
  299.     register struct tcp_rtt *tp;
  300.  
  301.     if(addr == 0)
  302.         return NULLRTT;
  303.     tp = &Tcp_rtt[(unsigned short)addr % RTTCACHE];
  304.     if(tp->addr != addr)
  305.         return NULLRTT;
  306.     return tp;
  307. }
  308.  
  309. /* TCP garbage collection - called by storage allocator when free space
  310.  * runs low. The send and receive queues are crunched. If the situation
  311.  * is red, the resequencing queue is discarded; otherwise it is
  312.  * also crunched.
  313.  */
  314. void
  315. tcp_garbage(red)
  316. int red;
  317. {
  318.     register struct tcb *tcb;
  319.     struct reseq *rp,*rp1;
  320.  
  321.     for(tcb = Tcbs;tcb != NULLTCB;tcb = tcb->next){
  322.         mbuf_crunch(&tcb->rcvq);
  323.         mbuf_crunch(&tcb->sndq);
  324.         for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  325.             rp1 = rp->next;
  326.             if(red){
  327.                 free_p(rp->bp);
  328.                 free((char *)rp);
  329.             } else {
  330.                 mbuf_crunch(&rp->bp);
  331.             }
  332.         }
  333.         if(red)
  334.             tcb->reseq = NULLRESEQ;
  335.     }
  336. }
  337.